package handler

import (
	"ehsm_kms/api"
	"ehsm_kms/internal/ehsm"
	"github.com/gin-gonic/gin"
)

func (h *Handler) createKey(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeySpec  int `json:"key_spec"  binding:"required"`
			Origin   int `json:"origin"  binding:"required"`
			KeyUsage int `json:"key_usage"  binding:"required"`
		} `json:"payload" binding:"required"`
	}{}
	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}
	resp := new(ehsm.CreateKeyResp)
	err := ehsm.CreateKeyAction.Call(ehsm.CreateKeyPayload{
		KeyUsage: req.Payload.KeyUsage, Origin: req.Payload.Origin, KeySpec: req.Payload.KeySpec},
		resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	err = h.cmkRep.Store(ctx, []byte(resp.Result.Cmk), req.Appid, req.Payload.KeyUsage, req.Payload.Origin, req.Payload.KeySpec)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	resp.Result.Cmk = ""
	api.HandleResp(ctx, resp)
	return
}
func (h *Handler) encrypt(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId     string `json:"keyid" binding:"required"`
			PlainText string `json:"plaintext" binding:"required"`
			Aad       string `json:"aad,omitempty" binding:"omitempty"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.EncryptResp)
	err = ehsm.EncryptAction.Call(ehsm.EncryptPayload{
		Cmk:       string(cmk),
		PlainText: req.Payload.PlainText,
		Aad:       req.Payload.Aad,
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}
func (h *Handler) decrypt(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId      string `json:"keyid" binding:"required"`
			CipherText string `json:"ciphertext" binding:"required"`
			Aad        string `json:"aad,omitempty" binding:"omitempty"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.DecryptResp)
	err = ehsm.DecryptAction.Call(ehsm.DecryptPayload{
		Cmk:        string(cmk),
		CipherText: req.Payload.CipherText,
		Aad:        req.Payload.Aad,
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) generateDataKey(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId  string `json:"keyid" binding:"required"`
			KeyLen int    `json:"keylen" binding:"required"`
			Aad    string `json:"aad,omitempty" binding:"omitempty"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.GenerateDataKeyResp)
	err = ehsm.DecryptAction.Call(ehsm.GenerateDataKeyPayload{
		Cmk:    string(cmk),
		KeyLen: req.Payload.KeyLen,
		Aad:    req.Payload.Aad,
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) generateDataKeyWithoutPlaintext(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId  string `json:"keyid" binding:"required"`
			KeyLen int    `json:"keylen" binding:"required"`
			Aad    string `json:"aad,omitempty" binding:"omitempty"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.GenerateDataKeyWithoutPlaintextResp)
	err = ehsm.DecryptAction.Call(ehsm.GenerateDataKeyPayload{
		Cmk:    string(cmk),
		KeyLen: req.Payload.KeyLen,
		Aad:    req.Payload.Aad,
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) sign(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId       string `json:"keyid" binding:"required"`
			Message     string `json:"message" binding:"required"`
			MessageType string `json:"message_type" binding:"required"`
			PaddingMode string `json:"padding_mode" binding:"required"`
			DigestMode  string `json:"digest_mode" binding:"required"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.SignResp)
	err = ehsm.SignAction.Call(ehsm.SignPayload{
		Cmk:         string(cmk),
		Message:     req.Payload.Message,
		MessageType: ehsm.MessageTypeMap.Get(req.Payload.MessageType),
		PaddingMode: ehsm.PaddingModeMap.Get(req.Payload.PaddingMode),
		DigestMode:  ehsm.DigestModeMap.Get(req.Payload.DigestMode),
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) verify(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId       string `json:"keyid" binding:"required"`
			Signature   string `json:"signature" binding:"required"`
			Message     string `json:"message" binding:"required"`
			MessageType string `json:"message_type" binding:"required"`
			PaddingMode string `json:"padding_mode" binding:"required"`
			DigestMode  string `json:"digest_mode" binding:"required"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.VerifyResp)
	err = ehsm.VerifyAction.Call(ehsm.VerifyPayload{
		Cmk:         string(cmk),
		Message:     req.Payload.Message,
		Signature:   req.Payload.Signature,
		MessageType: ehsm.MessageTypeMap.Get(req.Payload.MessageType),
		PaddingMode: ehsm.PaddingModeMap.Get(req.Payload.PaddingMode),
		DigestMode:  ehsm.DigestModeMap.Get(req.Payload.DigestMode),
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) asymmetricEncrypt(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId       string `json:"keyid" binding:"required"`
			PlainText   string `json:"plaintext" binding:"required"`
			PaddingMode string `json:"padding_mode" binding:"required"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.AsymmetricEncryptResp)
	err = ehsm.AsymmetricEncryptAction.Call(ehsm.AsymmetricEncryptPayload{
		Cmk:         string(cmk),
		PlainText:   req.Payload.PlainText,
		PaddingMode: ehsm.PaddingModeMap.Get(req.Payload.PaddingMode),
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) asymmetricDecrypt(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId       string `json:"keyid" binding:"required"`
			CipherText  string `json:"ciphertext" binding:"required"`
			PaddingMode string `json:"padding_mode" binding:"required"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.AsymmetricDecryptResp)
	err = ehsm.AsymmetricDecryptAction.Call(ehsm.AsymmetricDecryptPayload{
		Cmk:         string(cmk),
		CipherText:  req.Payload.CipherText,
		PaddingMode: ehsm.PaddingModeMap.Get(req.Payload.PaddingMode),
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) exportDataKey(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId          string `json:"keyid" binding:"required"`
			UKeyId         string `json:"ukeyid" binding:"required"`
			OldDataKeyBase string `json:"olddatakey_base" binding:"required"`
			Aad            string `json:"aad,omitempty" binding:"omitempty"`
			PaddingMode    string `json:"padding_mode,omitempty"  binding:"omitempty"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	oCmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.UKeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	reqE := ehsm.ExportDataKeyPayload{
		Cmk:        string(cmk),
		UKey:       string(oCmk),
		Aad:        req.Payload.Aad,
		OldDataKey: req.Payload.OldDataKeyBase,
	}
	if req.Payload.PaddingMode != "" {
		reqE.PaddingMode = ehsm.PaddingModeMap.Get(req.Payload.PaddingMode)
	}
	resp := new(ehsm.Resp)
	err = ehsm.GetPublicKeyAction.Call(reqE, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	api.HandleResp(ctx, resp)
}

func (h *Handler) getPublicKey(ctx *gin.Context) {
	req := struct {
		Req
		Payload struct {
			KeyId string `json:"keyid" binding:"required"`
		} `json:"payload" binding:"required"`
	}{}

	if err := ctx.Bind(&req); err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	cmk, err := h.cmkRep.FindByKeyId(ctx, req.Appid, req.Payload.KeyId)
	if err != nil {
		api.HandleError(ctx, 400, err, nil)
		ctx.Abort()
		return
	}

	resp := new(ehsm.Resp)
	err = ehsm.GetPublicKeyAction.Call(ehsm.GetPublicKeyPayload{
		Cmk: string(cmk),
	}, resp)
	if err != nil {
		api.HandleError(ctx, 500, err, nil)
		ctx.Abort()
		return
	}
	resp.Result["keyid"] = req.Payload.KeyId
	api.HandleResp(ctx, resp)
}
